package com.fulihui.wgj.schedule.filter;

import com.fulihui.common.util.IpAddressUtil;
import com.fulihui.wgj.schedule.annotation.MutexLock;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * spring Scheduling 集群 拦截器
 *
 * @author: Levon
 * @version: v 0.1 2018-06-11 15:03
 */
@Component
@Aspect
public class MutexLockFilter implements EnvironmentAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(MutexLockFilter.class);

    @Autowired
    CuratorFramework curatorFramework;

    Environment environment;

    /**
     * @param point     切点
     * @param mutexLock 分布式锁
     */
    @Around("@annotation(mutexLock)")
    public void around(ProceedingJoinPoint point, MutexLock mutexLock) {

        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        Object pointTarget = point.getTarget();
        Class<?> targetClass = pointTarget.getClass();
        LOGGER.info("job process, class=[{}], method=[{}]", targetClass.getName(), method.getName());

        String localIp = IpAddressUtil.getLocalIp();
        String localHostName = IpAddressUtil.getLocalHostName();
        LOGGER.info("ip=[{}], hostName=[{}]", localIp, localHostName);

        String node = parsePlaceHolder(mutexLock.node());

        int timeout = mutexLock.timeout();
        InterProcessMutex lock = new InterProcessMutex(curatorFramework, node);
        try {
            boolean acquire = lock.acquire(timeout, TimeUnit.SECONDS);
            if (acquire) {
                LOGGER.info("lock.acquire true, proceed!");
                point.proceed();
            } else {
                LOGGER.info("lock.acquire false, return!");
                return;
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        } finally {
            try {
                lock.release();
            } catch (Exception e) {
                LOGGER.error("lock.release error={}", e.getMessage(), e);
            }
        }
    }

    /**
     * 从环境读取配置
     *
     * @param pro
     * @return
     */
    private String parsePlaceHolder(String pro) {
        if (pro != null && pro.contains(PropertySourcesPlaceholderConfigurer.DEFAULT_PLACEHOLDER_PREFIX)) {
            String value = environment.getProperty(pro.substring(2, pro.length() - 1));
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("find placeholder value " + value + " for key " + pro);
            }
            if (null == value) {
                throw new IllegalArgumentException("property " + pro + " can not find!!!");
            }
            return value;
        }
        return pro;
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }
}
